// Package models 数据模型定义包
// 包含应用程序中使用的所有数据模型结构体
// 负责定义应用程序与数据库表之间的映射关系
// 包含基本字段约束、关联关系和生命周期钩子函数
package models

import (
	"fmt"
	"time"

	"gorm.io/gorm"
)

// UserModel 用户模型结构体，映射到数据库中的users表
// 表示系统中的用户实体，包含基本用户信息
// GORM会自动将结构体名称转换为复数形式作为表名，即users表
// 表名映射规则：默认将结构体名称转换为蛇形复数，UserModel -> user_models，
// 但本项目中通过GORM的约定使用了users表名（查看全局连接配置是否有表名禁用复数设置）
type UserModel struct {
	ID        int64     `gorm:"primaryKey"`              // 主键ID，自动递增（GORM默认将名为ID的字段设为主键）
	Name      string    `gorm:"size:16;not null;unique"` // 用户名，最大长度16字符，不能为空且唯一（确保用户名唯一性）
	Age       int       `gorm:"default:18"`              // 年龄，默认值为18（当不提供年龄值时自动使用默认值）
	Money     int       `json:"money"`
	CreatedAt time.Time // 创建时间，GORM会自动设置为记录创建时的时间（自动填充）
	//DeletedAt gorm.DeletedAt `gorm:"index"` // 启用软删除（如果需要软删除功能，可以取消注释）
	// 如果启用软删除，GORM会自动添加deleted_at字段并在查询时过滤掉已删除的记录
	UserDetailModel *UserDetailModel `gorm:"foreignKey:UserID"` // 一对一级联关系，UserModel拥有一个UserDetailModel
	// UserDetailModel是指向用户详情的指针，实现一对一级联查询
}

// UserDetailModel 用户详情模型，映射到数据库中的user_details表
// 用于存储用户的详细信息，与UserModel形成一对一关联
// 通过外键UserID与UserModel建立关联
// 一对一关系的定义：UserModel有一个UserDetailModel，UserDetailModel属于一个UserModel
type UserDetailModel struct {
	ID     int64 `gorm:"primaryKey"`           // 主键ID，自动递增
	UserID int64 `gorm:"not null;uniqueIndex"` // 外键，关联UserModel的ID字段，唯一索引确保一对一关系
	// uniqueIndex约束确保每个UserID在user_details表中只能出现一次，从而保证一对一关系
	Email     string     `gorm:"size:32"`           // 邮箱地址，最大长度32字符
	UserModel *UserModel `gorm:"foreignKey:UserID"` // 反向关联，通过UserModel字段可以从UserDetailModel访问到所属的UserModel
}

// BeforeCreate 创建记录前的钩子函数
// GORM的生命周期钩子函数之一，在创建用户记录之前自动调用
// 可用于数据验证、格式化、默认值设置或其他预处理操作
// 该函数是GORM的回调机制的一部分，能够在数据库操作前拦截并处理数据
//
// 参数:
//
//	tx - 数据库事务对象，可以用于执行额外的数据库操作，如关联表的处理
//
// 返回值:
//
//	error - 如果返回非nil错误，将中断创建操作，事务会回滚
func (u *UserModel) BeforeCreate(tx *gorm.DB) error {
	// 打印创建钩子函数执行信息，用于调试和日志记录
	fmt.Println("创建用户记录的钩子函数被调用")

	// 可以在这里添加数据预处理逻辑
	// 例如：
	// u.Name = strings.TrimSpace(u.Name) // 去除用户名两端空格
	// u.Name = "枫枫" // 设置默认用户名

	// 返回nil表示继续执行创建操作，允许事务提交
	return nil

	// 如果需要中断操作，可以返回错误：
	// return errors.New("创建用户失败")
}

// BeforeUpdate 更新记录前的钩子函数
// GORM的生命周期钩子函数，在更新用户记录之前自动调用
// 可用于数据验证、数据变更记录、时间戳更新等操作
// 适用于需要在数据更新前执行的任何逻辑处理
//
// 参数:
//
//	tx - 数据库事务对象，可用于执行额外的数据库操作或事务管理
//
// 返回值:
//
//	error - 如果返回非nil错误，将中断更新操作，事务会回滚
func (u *UserModel) BeforeUpdate(tx *gorm.DB) (err error) {
	// 打印更新钩子函数执行信息，用于调试和日志记录
	fmt.Println("更新的钩子函数")
	// 可以添加更新前的验证逻辑、数据转换或其他处理
	return nil
}

// BeforeDelete 删除前的钩子函数
// GORM的生命周期钩子函数，在删除用户记录之前自动调用
// 可用于数据备份、级联删除确认、权限验证等操作
// 适用于需要在数据删除前执行的任何逻辑处理
//
// 参数:
//
//	tx - 数据库事务对象，可用于执行额外的数据库操作，如级联删除相关记录
//
// 返回值:
//
//	error - 如果返回非nil错误，将中断删除操作，事务会回滚
func (u *UserModel) BeforeDelete(tx *gorm.DB) (err error) {
	// 打印删除钩子函数执行信息，用于调试和日志记录
	fmt.Println("删除钩子")
	// 可以添加删除前的确认逻辑、数据备份或其他处理
	return
}

// AfterFind 查询后的钩子函数
// GORM的生命周期钩子函数，在查询用户记录之后自动调用
// 可用于数据转换、字段解密、关联数据处理等操作
// 适用于需要在数据查询后对结果进行后处理的场景
//
// 参数:
//
//	tx - 数据库事务对象，可用于执行额外的数据库查询操作
//
// 返回值:
//
//	error - 如果返回非nil错误，将会影响查询结果
func (u *UserModel) AfterFind(tx *gorm.DB) (err error) {
	// 打印查询钩子函数执行信息，用于调试和日志记录
	fmt.Println("查询钩子")
	// 可以添加查询后的结果处理、数据转换或其他后处理逻辑
	return
}
